//
//  YHBaseViewController.swift
//  Adorbee
//
//  Created by amovision on 2024/11/25.
//

import UIKit
#if canImport(Alamofire)
import Alamofire
#endif

public struct YHNavigationItem {
  
  public enum Style {
    case title, image, view
  }
  
  public let button: UIButton
  public let size: CGSize
  public let spacing: CGFloat
  public let style: Style
  
  public static func title(_ title: Any, maxWidth: CGFloat = .infinity, spacing: CGFloat = 0) -> Self {
    let titles = AString.strings(title, fonts: UIFont.num(16, .semibold), colors: [Theme.light, UIColor.label2])
    let size = CGSizeMake(min(titles.first!.width + 16, maxWidth), 44)
    let button = UIButton(titles: titles, states: [.normal,.disabled])
    button.titleLabel?.numberOfLines = 0
    button.titleLabel?.minimumScaleFactor = 0.7
    button.titleLabel?.adjustsFontSizeToFitWidth = true
    return Self(button: button, size: size, spacing: spacing, style: .title)
  }
  public static func image(_ image: Any, size: CGSize = .zero, spacing: CGFloat = 0) -> Self {
    let img = UIImage.named(image, size: size)
    let button = UIButton(image: img)
    let contentMode: UIView.ContentMode = (img?.width ?? 0) <= 44 ? .center : .scaleAspectFit
    let sz = if let img { CGSizeMake(max(img.whRatio, 1)*44, 44) } else { [44].size }
    button.contentMode = contentMode
    return Self(button: button, size: sz, spacing: spacing, style: .image)
  }
  public static func view(_ view: UIView, size: CGSize = .zero, spacing: CGFloat = 0) -> Self {
    let sz = size != .zero ? size : view.frame.size
    let button = UIButton()
#if canImport(SnapKit)
    view.makeConstraints(on: button) { make in
      make.center.equalToSuperview()
      make.size.equalTo(view.frame.size)
    }
#endif
    return Self(button: button, size: sz, spacing: spacing, style: .view)
  }
}

public enum YHControllerState: Int {
  case initial, appear, disappear, deinitial
  public var onTop: Bool { self == .initial || self == .appear }
}

open class YHBaseViewController: UIViewController {
  public var eventBlock: YHOptAnyBlock? = nil
    
  public var userInfo: Any?
  
  public var showErrorView = false {
    didSet {
#if canImport(Alamofire)
      netErrorView.isHidden = !showErrorView || NetworkReachabilityManager.default!.isReachable
#else
      netErrorView.isHidden = !showErrorView
#endif
    }
  }
    
  private lazy var netErrorView = YHNetworkErrorView()
    
  private let rightBtnTag = 2907390
  private let leftBtnTag = 84949202
    
  public private(set) var state: YHControllerState = .initial
  private var isGesteCanceled: Bool = false
  public let navigationBar = UIView(color: .dynamic(.white, .gray("1C")))
  public let navigationSeperator = UIView(color: .quaternaryLabel)
  public var removedAfterPush: Bool = false
  public private(set) var yh_movingFromParent: Bool = false
  public private(set) lazy var returnButton: UIButton = {
    let btn = UIButton(image: "nav_arrow")
    btn.addAction(#selector(returnButtonAction), target: self)
    btn.isHidden = navigationController == nil || navigationController?.viewControllers.first == self
    btn.contentHorizontalAlignment = .left
    return btn
  }()
    
  public override var title: String? {
    didSet {
      super.title = title
      titleLabel.text = title
    }
  }
    
  public var titleView: UIView? {
    didSet {
      oldValue?.removeFromSuperview()
      guard let titleView else { return }
      navigationBar.addSubview(titleView)
      let max_w = (YHScreenW - (20+44) * 2)
      let h = min(titleView.frame.height > 0 ? titleView.frame.height : 44, 44)
      let w = min(titleView.frame.width > 0 ? titleView.frame.width : max_w, max_w)
#if canImport(SnapKit)
      titleView.makeConstraints { make in
        make.centerX.equalToSuperview()
        make.top.equalTo(YHStatusBarHeight - ((h - 44)/2))
        make.height.equalTo(h)
        make.width.equalTo(w)
      }
#endif
    }
  }
    
  public private(set) var leftButtons: [UIButton]?
    
  public private(set) var rightButtons: [UIButton]?
  
  private func setNavigationItems(_ items: [YHNavigationItem]?, isLeft: Bool) {
    if isLeft { leftButtons?.forEach { $0.removeFromSuperview() } }
    else { rightButtons?.forEach { $0.removeFromSuperview() } }
    var button: UIButton? = nil
    let navigationItems = items?.enumerated().map { idx, item in
      let btn = item.button
      if isLeft {
        btn.addAction(#selector(leftButtonAction(_:)), target: self)
        btn.tag = leftBtnTag + idx
      } else {
        btn.addAction(#selector(rightButtonAction(_:)), target: self)
        btn.tag = rightBtnTag + idx
      }
      navigationBar.addSubview(btn)
#if canImport(SnapKit)
      btn.makeConstraints { make in
        if let button {
          if isLeft {
            make.left.equalTo(button.snp.right).offset(item.spacing)
          } else {
            make.right.equalTo(button.snp.left).offset(-item.spacing)
          }
        } else {
          let space: CGFloat = item.style == .title ? 8 : 16
          if isLeft {
            if returnButton.isHidden {
              make.left.equalTo(item.spacing+space)
            } else {
              make.left.equalTo(returnButton.snp.right).offset(item.spacing)
            }
          } else {
            make.right.equalTo(-item.spacing-space)
          }
        }
        make.bottom.equalTo(0)
        make.size.equalTo(item.size)
      }
#endif
      button = btn
      return btn
    }
    if isLeft { leftButtons = navigationItems }
    else { rightButtons = navigationItems }
  }
  
  public var rightItems: [YHNavigationItem]? {
    didSet {
      setNavigationItems(rightItems, isLeft: false)
    }
  }
    
  public var leftItems: [YHNavigationItem]? {
    didSet {
      setNavigationItems(leftItems, isLeft: true)
    }
  }
    
  public let titleLabel = UILabel(font: .num(17, .semibold), color: .label, lines: 2, aligment: .center, scale: 0.7)
    
  public var viewWillDisappearBlock: ((YHControllerState, Bool) -> ())?
  public var viewWillAppearBlock: ((YHControllerState, Bool) -> ())?
    
  convenience public init(_ userInfo: Any?, eventBlock: YHOptAnyBlock? = nil) {
    self.init()
    self.userInfo = userInfo
    self.eventBlock = eventBlock
  }
    
  @objc open func returnButtonAction() {
    pop()
  }
    
  open func rightItemsAction(_ idx: Int) {}
  open func leftItemsAction(_ idx: Int) {}
    
  @objc private func rightButtonAction(_ btn: UIButton) {
    rightItemsAction(btn.tag - rightBtnTag)
  }

  @objc private func leftButtonAction(_ btn: UIButton) {
    leftItemsAction(btn.tag - leftBtnTag)
  }
  
  open override func viewDidLoad() {
    super.viewDidLoad()
    LOGI("[\(NSStringFromClass(Self.self)) viewDidLoad]")
    fd_prefersNavigationBarHidden = true
    setupNavigationBar()
    setupLocalUI()
    setupUI()
    eventHandle()
    popNetError()
  }
    
  private func setupLocalUI() {
    view.addSubview(netErrorView)
#if canImport(SnapKit)
    netErrorView.makeConstraints { make in
      make.left.right.equalTo(0)
      make.top.equalTo(navigationBar.snp.bottom)
      make.height.equalTo(44)
    }
#endif
  }
    
  public func popNetError() {
    view.bringSubviewToFront(netErrorView)
#if canImport(Alamofire)
      netErrorView.isHidden = !showErrorView || NetworkReachabilityManager.default!.isReachable
#else
      netErrorView.isHidden = !showErrorView
#endif
  }
    
  open func setupUI() {}
  open func eventHandle() {}
  open func networkDidChanged() {}
    
  open override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    LOGI("[\(NSStringFromClass(Self.self)) viewWillAppear]")
    yh_movingFromParent = false
    state = isMovingToParent ? .initial : .appear
    viewWillAppearBlock?(state, isGesteCanceled)
    isGesteCanceled = false
  }
    
  open override func willMove(toParent parent: UIViewController?) {
    super.willMove(toParent: parent)
    yh_movingFromParent = parent == nil
  }
    
  open override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    guard let nav = navigationController,
          let i = nav.viewControllers.firstIndex(of: self) else { return }
    let idx = i - 1
    guard 0 ..< nav.viewControllers.count ~= idx else { return }
    guard let pushVC = nav.viewControllers[idx] as? YHBaseViewController,
          pushVC.removedAfterPush else { return }
    let vcs = nav.viewControllers.filter { $0 != pushVC }
    nav.setViewControllers(vcs, animated: false)
  }
    
  open override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    
    state = yh_movingFromParent ? .deinitial : .disappear
    if transitionCoordinator?.isInteractive == true {
      transitionCoordinator?.notifyWhenInteractionChanges { [weak self] ctx in
        guard let self else { return }
        isGesteCanceled = ctx.isCancelled
        viewWillDisappearBlock?(state, isGesteCanceled)
        LOGI("[\(NSStringFromClass(Self.self)) viewWillDisappear state: \(state), isGesteCanceled: \(isGesteCanceled)]")
      }
    } else {
      viewWillDisappearBlock?(state, false)
      LOGI("[\(NSStringFromClass(Self.self)) viewWillDisappear state: \(state), isGesteCanceled: \(false)]")
    }
  }
    
  private func setupNavigationBar() {
    view.backgroundColor = .dynamic(.gray("F5"), .black)
    view.addSubview(navigationBar)
    navigationBar.addSubviews([returnButton,navigationSeperator])
    titleView = titleLabel
#if canImport(SnapKit)
    returnButton.makeConstraints { make in
      make.left.equalTo(16)
      make.top.equalTo(YHStatusBarHeight)
      make.size.equalTo([44].size)
    }
    navigationBar.makeConstraints { make in
      make.top.left.right.equalTo(0)
      make.height.equalTo(YHNaviBarHeight)
    }
    navigationSeperator.snp.makeConstraints { make in
      make.left.right.equalTo(0)
      make.bottom.equalTo(0)
      make.height.equalTo(0.5)
    }
#endif
    addNotification(.networkChanged) { [weak self] _, _ in
      guard let self else { return }
      popNetError()
      networkDidChanged()
    }
  }
    
  deinit {
    LOGI("[\(NSStringFromClass(Self.self)) deinit]")
    removeNotifications()
  }
}

public class YHNetworkErrorView: UIView {
  convenience init() {
    self.init(frame: .zero)
    backgroundColor = .rgb(237, 225, 210)
    let spk = UIImageView(named: "net_spk")
    let label = UILabel("The current phone has no network signal. Please kindly check.".local, font: .num(14, .semibold), color: .label1, lines: 2)
    let close = YHEnlargeButton(image: "net_close") { [unowned self] _ in
      isHidden = true
    }
    addSubviews([spk, label, close])
#if canImport(SnapKit)
    spk.makeConstraints { make in
      make.left.equalTo(16)
      make.size.equalTo([20].size)
      make.centerY.equalToSuperview()
    }
    label.makeConstraints { make in
      make.left.equalTo(spk.snp.right).offset(8)
      make.right.equalTo(close.snp.left).offset(-8)
      make.centerY.equalToSuperview()
    }
    close.makeConstraints { make in
      make.right.equalTo(-16)
      make.centerY.equalToSuperview()
      make.size.equalTo([20].size)
    }
#endif
  }
}
